package com.gzdev.disk.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.gzdev.disk.constant.SysConstant;
import com.gzdev.disk.entity.Files;
import com.gzdev.disk.entity.Groups;
import com.gzdev.disk.mapper.FilesMapper;
import com.gzdev.disk.mapper.GroupsMapper;
import com.gzdev.disk.response.ErrorCode;
import com.gzdev.disk.response.Result;
import com.gzdev.disk.response.Results;
import com.gzdev.disk.service.IFileService;
import com.gzdev.disk.utils.NovelWebUtils;
import com.gzdev.disk.service.FileUpload;
import cn.novelweb.tool.upload.local.pojo.UploadFileParam;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.gzdev.disk.dto.AddFileDto;
import com.gzdev.disk.dto.GetFileDto;
import com.gzdev.disk.utils.EmptyUtils;
import com.gzdev.disk.utils.UuidUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.List;

/**
 * <p>
 * 文件上传下载 服务实现类
 * </p>
 *
 * @author LEON
 * @since 2020-05-29
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class FileServiceImpl implements IFileService {

    private final FilesMapper filesMapper;
    private final GroupsMapper groupsMapper;
    @Value("${file.save-path:/data-center/files/gzdev-disk}")
    private String savePath;
    @Value("${file.conf-path:/data-center/files/gzdev-disk/conf}")
    private String confFilePath;

    @Override
    public Result<List<GetFileDto>> getFileList(Integer pageNo, Integer pageSize, String appId, String groupId) {
        try{
            PageHelper.startPage(pageNo, pageSize);
            if(groupId == null || groupId.isEmpty())
                return Results.newFailResult(ErrorCode.INVALID_PARAMETER, "groupId不能为空");
            if(groupId.equals("all")) //为all查询所有
                groupId = "";
            List<GetFileDto> result = filesMapper.selectFileList(appId, groupId);
            PageInfo<GetFileDto> pageInfo = new PageInfo<>(result);
            return Results.newSuccessResult(pageInfo.getList(), "查询成功", pageInfo.getTotal());
        }catch (Exception e){
            log.error("获取文件列表出错", e);
        }
        return Results.newFailResult(ErrorCode.DB_ERROR, "查询失败");
    }

    @Override
    public Result<String> uploadFiles(MultipartFile file) {
        try {
            String fileName = file.getOriginalFilename();
            if (EmptyUtils.basicIsEmpty(fileName)) {
                return Results.newFailResult(ErrorCode.FILE_ERROR, "文件名不能为空");
            }
            if(file.getSize() > SysConstant.MAX_SIZE){
                return Results.newFailResult(ErrorCode.FILE_ERROR, "文件过大，请使用大文件传输");
            }
            String suffixName = fileName.contains(".") ? fileName.substring(fileName.lastIndexOf(".")) : null;
            String newName = UuidUtils.uuid() + suffixName;
            // 重命名文件
            File newFile = new File(savePath, newName);
            // 如果该存储路径为空则新建存储路径
            if (!newFile.getParentFile().exists()) {
                newFile.getParentFile().mkdirs();
            }
            // 文件写入
            file.transferTo(newFile);
            // 保存文件信息
            Files files = new Files()
                    .setFilePath(newName)
                    .setFileName(fileName)
                    .setSuffix(suffixName == null ? null : suffixName.substring(1))
                    .setFileSize(file.getSize())
                    .setUploader("");
            filesMapper.insert(files);
            return Results.newSuccessResult(files.getId(), "上传完成");
        } catch (Exception e) {
            log.error("上传协议文件出错", e);
        }
        return Results.newFailResult(ErrorCode.FILE_ERROR, "上传失败");
    }

    @Override
    public Result checkFileMd5(String md5, String fileName) {
        try {
            cn.novelweb.tool.http.Result result = FileUpload.checkFileMd5(md5, fileName, confFilePath, savePath);
            return NovelWebUtils.forReturn(result);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
        return Results.newFailResult(ErrorCode.FILE_UPLOAD, "上传失败");
    }

    @Override
    public Result breakpointResumeUpload(UploadFileParam param, HttpServletRequest request) {
        try {
            // 这里的 chunkSize(分片大小) 要与前端传过来的大小一致
            cn.novelweb.tool.http.Result result = FileUpload.fragmentFileUploader(param, confFilePath, savePath, 5242880L, request);
            return NovelWebUtils.forReturn(result);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
        return Results.newFailResult(ErrorCode.FILE_UPLOAD, "上传失败");
    }

    @Override
    public Result<String> addFile(AddFileDto dto) {
        try {
            Files file = new Files();
            BeanUtils.copyProperties(dto, file);

            GetFileDto fd = filesMapper.selectFileInfo(dto.getFileMd5() + "_" + dto.getFileName());
            String fileId = null;
            if(fd != null && fd.getId() != null){
                fileId = fd.getId();
            }else if(filesMapper.insert(file.setFilePath(dto.getFileMd5() + "_" +  dto.getFileName())) == 1){
                fileId = file.getId();
            }
            if(fileId != null){
                Groups group = new Groups();
                BeanUtils.copyProperties(dto, group);
                group.setFileId(fileId);
                groupsMapper.insert(group);
                return Results.newSuccessResult(null, "添加成功");
            }
        } catch (Exception e) {
            log.error("添加文件出错", e);
        }
        return Results.newFailResult(ErrorCode.FILE_UPLOAD, "添加失败");
    }

    @Override
    public InputStream getFileInputStream(String id) {
        try {
            Files files = filesMapper.selectById(id);
            File file = new File(savePath + File.separator + files.getFilePath());
            return new FileInputStream(file);
        } catch (Exception e) {
            log.error("获取文件输入流出错", e);
        }
        return null;
    }

    @Override
    public Result<Files> getFileDetails(String id) {
        try {
            Files files = filesMapper.selectById(id);
            return Results.newSuccessResult(files, "查询成功");
        } catch (Exception e) {
            log.error("获取文件详情出错", e);
        }
        return Results.newFailResult(ErrorCode.DB_ERROR, "查询失败");
    }
}
